home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
yerk
/
mps231ss.hqx
/
Mops ƒ
/
Modules
< prev
next >
Wrap
Text File
|
1993-02-20
|
11KB
|
428 lines
\ This file implements relocatable modules. In installed applications,
\ these become separate code segments.
true value CLEANMOD?
false value RELEASED?
0 value THIS_MOD
0 value LAST_MOD
0 value SVDP
0 value SVLATEST
0 value MODSTART
string $EXP
string $CXT
\ variable SAVE_CONTEXT 8 4 * allot
: UNMOD \ Puts things back to normal after a module
\ or stand-alone code compilation
svDP 0EXIT \ Out if we're not compiling a module/SA
svLatest -> latest
svDP -> DP 0 -> svDP 0 -> compMod
nil?: $cxt NIF ptr: $cxt context 32 cmove release: $cxt THEN
false -> SAcomp? ;
: >NXTEXP \ ( n -- )
modstart - pad ! pad 4 add: $exp ;
:class MODULE super{ object }
handle MODHDL
byte EXEC_CNT \ Must be at an even offset since we sometimes
bool LOCKED? \ do a combined access to exec_cnt and locked?
byte FLAGS
int RES#
int #IMP
dicaddr LASTIMP
dicaddr LOADPOINT
var DicDateTime
int RELOFFS
int INSTALL?
:m BASE:
nil?: modHdl IF 0 EXIT THEN
nptr: modHdl ;m
:m HANDLE: get: modHdl ;m
:m .ID: ^base obj> .id ;m
:m SETRELEASE: \ ( addr -- )
modbase - put: relOffs ;m
:m SETRESID: \ ( resID -- )
put: res# ;m
:m INSTALL?: get: install? ;m
:m SETINSTALL: put: install? ;m
\ :m EXPORTS_CLASS: addr: flags 2 bset ;m
\ KLUDGE: and UNKLUDGE: may be used when we save a dic image, to mark
\ a module as unloaded in the saved image without really unloading it.
:m KLUDGE: \ ( -- modHdl flags exec+locked? )
get: modHdl get: flags addr: exec_cnt w@ nilH put: modHdl ;m
:m UNKLUDGE: \ ( modHdl flags exec+locked? -- )
addr: exec_cnt w! put: flags put: modHdl ;m
:m GETNAME: \ ( -- addr len )
^base obj> >name n>count ;m
:m EXTNAME: { xaddr xlen \ len -- addr' len' }
getName: self -> len pad len cmove
xaddr pad len + xlen cmove \ Add extension
pad len xlen + ;m
:m BINNAME: \ ( -- addr len ) Leaves name of binary file for module.
" .BIN" extName: self ;m
:m TXTNAME: \ ( -- addr len ) Leaves name of text file for module.
" .TXT" extName: self ;m
:m LOAD: { \ rc -- } \ Loads if not loaded already
nil?: modHdl 0EXIT
get: res#
IF
'type CODE get: res# getRes dup 0= ?error 138
put: modHdl
ELSE
binName: self name: fFcb 0 setVref: fFcb
openReadOnly: fFcb ?error 138
['] pause 4+ @ 0 -> pause \ Disable pause over read to avoid
\ possible reentrancy
size: fFcb dup new: modHdl
lock: modHdl \ Maybe we need this
ptr: modHdl swap read: fFcb -> rc
['] pause 4+ ! \ Restore pause
unlock: modHdl \ Unlock before error check
close: fFcb drop rc ?error 141
base: self @ get: dicDateTime u<
IF \ BIN file is old version
release: modHdl 148 die
THEN
THEN
moveHi: modHdl \ Move module hi since it gets locked
clear: exec_cnt ;m
:m RELEASE: { \ svModbase -- }
clear: exec_cnt \ We certainly hope we know what we're
clear: locked? \ doing!!
get: modHdl nilH = ?EXIT \ Out if not loaded
get: relOffs -1 <> \ Any module-specific action?
IF \ Yes
lock: modHdl \ We're going to execute in the module
modbase -> svModbase
ptr: modHdl 32766 + dup -> modbase
get: relOffs +
execute \ Execute the appropriate word
svModbase -> modbase \ No need to unlock since we're
\ just about to release
THEN
get: res# \ Resource?
IF
get: modHdl trap$ a9a3 \ call ReleaseResource
nilH put: modHdl
ELSE
release: modHdl
THEN
true -> released? ;m
\ KEEP: and DROP: flag this module as needed and not needed, respectively.
\ The main purpose of this flagging is that if GETSPACE is called, loaded
\ modules will be released to make room, unless they have been flagged as
\ needed by KEEP:. But note that RELEASE: ignores the flag, so that we
\ can get rid of a module by force if necessary. This may happen if there
\ was a crash while the module was executing.
\ LOCK: is more drastic than KEEP:, since it means that this module becomes
\ non-relocatable. UNLOCK: reverses a LOCK:. Note that DROP: in effect does
\ an UNLOCK: as well.
\ This "locking" feature is used for ExtrasMod, which has a window, and
\ for the debugger and printMod, which can be entered through the back
\ door (via a vect or a trap). (By the way, we hope we won't have to do this
\ back door business anywhere else. Entering a module through the back door
\ is not usually a very safe thing to do.) Locking a module can give
\ a useful performance improvement if a module is to be called several times
\ in succession, since we bypass the _HLock and _Hunlock calls if the module
\ is marked locked.
:m KEEP:
addr: flags 1 bset ;m
:m DROP:
get: exec_cnt NIF unlock: modHdl THEN \ Unlock if not executing
addr: flags 1 breset clear: locked? ;m
:m LOCK:
true put: locked? load: self lock: modHdl ;m
\ Note: loading does a MoveHi so we don't need to do it again.
:m UNLOCK:
false put: locked?
get: exec_cnt NIF nil?: modHdl NIF unlock: modHdl THEN THEN ;m
:m KEEP?:
get: exec_cnt 0<> get: flags or ;m
:m LOCKED?:
get: exec_cnt get: locked? or ;m
:m ?RELEASE:
keep?: self ?EXIT
release: self ;m
:m #IMP: get: #imp ;m
:m GETIMPORTS: { \ n -- }
0 -> n
BEGIN
header -92 w, \ Header with handler code for imported word
^base compimp 1 ++> n
& } endlist?
UNTIL
n 1- put: #imp
latest name> put: lastimp
here put: loadpoint ;m
\ ====================================
private \ These methods are used only by compile:
\ ====================================
:m ExpSupers: { ^nw -- }
BEGIN
^nw @ 0EXIT
^nw relocType InThisMod =
IF ^nw @abs mfa displace expMethods: [self] THEN
4 ++> ^nw
AGAIN ;m
public
\ This gets called via a late bind, so must be public
:m ExpMethods: { maddr -- }
BEGIN \ Loop thru methods in this class
maddr @ 0>=
IF \ We've come to the superclasses
maddr expSupers: self EXIT
THEN
\ Next method
maddr 10 + >nxtExp
maddr 4+ displace -> maddr
AGAIN ;m
private
mlocal !EXPORTS: { \ thisImp thisCfa maddr -- }
:m ?!CLASS: \ If this exported item is a class, we set the handler
\ code of the imported version and add the method entry offsets
\ to the export table.
thisCfa 2- w@x -58 = 0EXIT \ Out if it isn't a class
-90 thisImp 2- w!
thisCfa ffa 1+ 1 bset
thisCfa mfa displace expMethods: self ;m
:m 1EXPORT:
next: theMark link> -> thisImp
thisImp >name n>count sFind
drop -> thisCfa
thisCfa thisImp =
IF \ Not defined
cr thisImp .id 2 spaces msg# 144
false -> cleanMod?
ELSE \ All OK. Put info into import definition:
thisCfa >name c@ thisImp >name c! \ Name flags
pos: $exp thisImp 4+ w! \ Export table index
thisCfa >nxtExp \ Add next exp tbl entry
?!class: self \ More stuff if it's a class
THEN ;m
:mloc !EXPORTS: \ { \ n thisImp thisCfa maddr -- }
get: #imp 0= ?error 143 \ Module has no exported names
clear: $exp
get: lastimp set: theMark
get: #imp FOR 1export: self NEXT
;mloc
public
:m COMPILE: { \ size newModbase -- }
compMod ?error 177 \ Error if already compiling a module
release: self \ Get rid of old version, if loaded
context 32 put: $cxt
dp -> svDP latest -> svLatest ^base -> compMod
get: loadpoint (forget) svDP -> dp
true -> cleanMod?
pushNew: loadFile
txtName: self name: topFile
here -> modstart
modstart 32766 + -> newModbase
16 reserve \ Reserve space for header and offset to exports table.
^base -> this_mod
newModbase LdFromMod
dateTime modstart ! \ Put source date in bin module header
getDirID: topFile modstart 4+ ! \ Also DirID of source file
drop: loadfile
0 -> this_mod
!exports: self
cleanMod?
IF \ Everything's OK. Now we have some final housekeeping:
here modstart 8 + displ! \ Store export table offs in header
all: $exp n, \ Add export table to end
here 4+ context - , \ Adjustment value for context copy
context 32 n, \ Add copy of Context to end (so the
\ decompiler/debugger can find words)
here modstart - -> size \ Size of module
size modstart 12 + ! \ Store size in header
binName: self name: fFcb \ Set name of binary file
create: fFcb ?error 139
'type BIN 'type MOPS set: fFcb \ Type and signature
modstart size write: fFcb \ Write out binary module
close: fFcb drop
IF
msg# 140 \ I/O error on writing bin file
ELSE
curs -curs
cr getName: fFcb type ." saved"
-> curs
THEN
THEN
unmod \ Also releases $cxt
release: $exp ;m
:m CLASSINIT:
-1 put: relOffs
dateTime put: dicDateTime ;m
;class
: SETRELEASE \ ( addr -- )
setRelease: this_mod ;
: MLD
dup load: ** ;
' mld -> modLoad
: MOD? \ ( cfa -- cfa b )
objCfa? NIF false EXIT THEN
dup >obj >classCfa ['] module = ;
: ?DISP { theCfa size -- } \ handler to release selected modules
theCfa mod? NIF drop EXIT THEN
free size < \ Do we still need space?
IF >obj ?release: module
ELSE drop
THEN ;
\ PURGE forcibly releases all modules, no matter what. It is a vector,
\ defined in file Base.
: (PRG) { theCfa size -- } \ unlock and release
theCfa mod? NIF drop EXIT THEN
>obj release: module ;
: (PURGE) ['] (prg) big# trav ;
' (purge) -> purge
: NEEDSPACE \ ( #bytes -- ) release modules until #bytes are available
false -> released?
freeblk drop ['] ?disp swap trav ;
: GS big# needSpace released? ;
' gs -> getSpace
: FROM \ ( -- ^mod sec# )
module \ Create module object
latest name> >obj dup -> last_mod 28 ;
: IMPORT{ \ ( ^mod sec# -- )
28 ?pairs getImports: ** ;
: EXPORTS_CLASS
last_mod exports_class: ** ;
\ Some imports, needed by what follows:
from PATHSMOD import{ OWP GETPATHS .PATHS }
from CALL1&LMOD import{ CallFirst CallLast (GET) (C1) (CL) }
from TOOL import{ CALL ASMCALL FCALL GLOBAL $>GLOB KONST $>KONST }
from ASMMOD import{ ASM :CODE :MCODE TOCODE }
:f OPEN_WITH_PATHS OWP ;f
compile: pathsMod
true -> use_paths?
" mops.paths" getPaths
' (get) -> get1st&last
' (C1) -> doCall1st
' (CL) -> doCallLast
compile: call1&Lmod
endload
+echo
:class HAHA super{ int }
callLast print:
:m BAtest:
1 2 3 . . . ;m
;class
:class SUBHAHA super{ haha }
callLast dump:
:m BAtest: -9 -8 -7 . . . ;m
;class
haha hh
subhaha ss
: q db batest: hh batest: ss ;
endload
: QQ ." QQ here. Hello. " ; \ This gets called from testMod
variable VB
from TESTMOD import{ AA BB CC CLASSX DD }
\ from TESTMOD2 import{ DD EE }
: QQ ." This is the wrong QQ!!!" ; \ This one shouldn't!
compile: testmod
\ compile: testmod2